#pragma once
#include <string>
#include <iostream>
#include <stdio.h>
#include <cstring>
#include <sstream>



using namespace std;

//Klasa odpowiedzialna za pakowanie, rozpakowywanie i przechowywanie pakietów zawierających tylko kod wiadomości
class Package {

protected:

public:

	Package() {}

	virtual ~Package(){};

	Package(int code_) :
		code(code_) {
	}
	;
	//Zmienna przechowujaca kod wiadomości
	unsigned int code;
	//Bufor używany do wysyłania danych
	char sendBuffor[256];

	virtual void pack(unsigned int i, char *dane, int buforSize) {
	}
	virtual void unpack(char *dane, int buforSize) {
	}
	virtual void pack(unsigned int i, unsigned int number_) {
	}
	virtual void unpack(unsigned int i, unsigned int number_) {
	}

	//Metoda umieszczająca dane w buforze - pierwszy bajt kod wiadomości
	virtual void pack() {

		memset(sendBuffor, 0, sizeof sendBuffor);
		sendBuffor[0] = (unsigned int) code;
	}
	//Metoda rozpakowująca bufor - odczytanie pierwszego bajtu i wpisanie go do zmiennej code
	virtual void unpack(unsigned int i) {
		code = i;
	}
};

//Klasa odpowiedzialna za pakowanie, rozpakowywanie i przechowywanie pakietów tekstowych
class ChatPackage: public Package {

public:
	string data;

	ChatPackage() {
	}
	;
	ChatPackage(int code_, string data_) :
		data(data_) {
		Package::code = code_;
	}
	;
	//Metoda umieszczająca dane w buforze - pierwszy bajt kod wiadomości, pozostałe bajty zawierają wiadomość tekstową
	void pack() {

		ostringstream ss;

		string pString;

		const char* tempChar;

		int stringSize;

		memset(sendBuffor, 0, sizeof sendBuffor);

		sendBuffor[0] = (unsigned int) code;

		ss << data;

		pString = ss.str();

		stringSize = pString.size();

		tempChar = pString.c_str();

		for (int i = 1; i <= stringSize; i++) {
			sendBuffor[i] = tempChar[i - 1];
		}

	}

	//Metoda rozpakowująca bufor - odczytanie pierwszego bajtu i wpisanie go do zmiennej code, reszta bajtów przepisana do stringa
	void unpack(char *dane, int buforSize) {
		ostringstream ss;
		code = dane[0];
		for (int f = 1; f < buforSize && dane[f] != 0; f++) {
			ss << dane[f];
		}
		data = ss.str();
	}

};

//Klasa odpowiedzialna za pakowanie, rozpakowywanie i przechowywanie pakietów z obrazkami
class ImagePackage: public Package {
	char * buffer;


public:
	char imageBuffer[38401];
	ImagePackage() {
	}
	;

	ImagePackage(int code_, char * buffer_) {
		memcpy(imageBuffer, buffer_, sizeof(imageBuffer));
		Package::code = code_;
	}
	;
	void pack() {
		memset(sendBuffor, 0, sizeof sendBuffor);
	}
	;
	//Metoda rozpakowująca bufor - odczytanie pierwszego bajtu i wpisanie go do zmiennej code, reszta bajtów przepisana
	//do bufora przechowującego obrazek
	void unpack(char *dane, int buforSize) {

		code = dane[0];
		for (int f = 0; f < buforSize; f++) {
			imageBuffer[f] = dane[f];
		}

	}
	;
	char * getBuffer() {
		return buffer;
	}
	;
};

//Klasa odpowiedzialna za pakowanie, rozpakowywanie i przechowywanie pakietów z numerami
class NumberPackage: public Package {

public:
	NumberPackage() {
	};

	NumberPackage(int code_, int number_) :
		number(number_) {
		Package::code = code_;
	};

	unsigned int number;

	//Metoda umieszczająca dane w buforze - pierwszy bajt kod wiadomości, drugi przekazywany numer
	void pack() {

		memset(sendBuffor, 0, sizeof sendBuffor);
		sendBuffor[0] = (unsigned int) code;
		sendBuffor[1] = (unsigned int) number;
	}
	;

	//Metoda rozpakowująca - pobiera wartość kodu wiadomości oraz przekazywany numer i zapisuje je w zmiennych code i number
	void unpack(unsigned int i, unsigned int number_) {
		code = i;
		number = number_;
	}
	;
};

